In [1]:
%matplotlib inline
In [2]:
import warnings
warnings.simplefilter(action="ignore", category=FutureWarning)
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from utils import *
In [3]:
pd.set_option("display.max_rows", 11)
pd.set_option("display.float_format", "{:.2f}".format)
Priprava dat¶
- nactu data z Excelu
- pripravim tabulku jednotlivych bloku
- pridam casovou dimenzi
In [4]:
yearly_params, sources_definition = read_parameters("./parametry.xlsx", 3)
yearly_params = yearly_params.set_index("Rocni cyklus")
In [5]:
blocks = prepare_table_blocks(sources_definition)
blocks
Out[5]:
| type | block_no | power | priority | shutdown_prob | |
|---|---|---|---|---|---|
| 0 | FVE | 0 | 2100.00 | 1 | 40 |
| 1 | Jadro | 0 | 716.67 | 2 | 10 |
| 2 | Jadro | 1 | 716.67 | 2 | 10 |
| 3 | Jadro | 2 | 716.67 | 2 | 10 |
| 4 | Jadro | 3 | 716.67 | 2 | 10 |
| ... | ... | ... | ... | ... | ... |
| 22 | Plyn | 3 | 287.50 | 4 | 20 |
| 23 | Plyn | 4 | 287.50 | 4 | 20 |
| 24 | Plyn | 5 | 287.50 | 4 | 20 |
| 25 | Plyn | 6 | 287.50 | 4 | 20 |
| 26 | Plyn | 7 | 287.50 | 4 | 20 |
27 rows × 5 columns
In [6]:
days = pd.DataFrame(pd.date_range(start="2022-01-01", end="2022-12-31", freq="D"), columns=["date"])
df_system = days.merge(blocks, how="cross")
df_system
Out[6]:
| date | type | block_no | power | priority | shutdown_prob | |
|---|---|---|---|---|---|---|
| 0 | 2022-01-01 | FVE | 0 | 2100.00 | 1 | 40 |
| 1 | 2022-01-01 | Jadro | 0 | 716.67 | 2 | 10 |
| 2 | 2022-01-01 | Jadro | 1 | 716.67 | 2 | 10 |
| 3 | 2022-01-01 | Jadro | 2 | 716.67 | 2 | 10 |
| 4 | 2022-01-01 | Jadro | 3 | 716.67 | 2 | 10 |
| ... | ... | ... | ... | ... | ... | ... |
| 9850 | 2022-12-31 | Plyn | 3 | 287.50 | 4 | 20 |
| 9851 | 2022-12-31 | Plyn | 4 | 287.50 | 4 | 20 |
| 9852 | 2022-12-31 | Plyn | 5 | 287.50 | 4 | 20 |
| 9853 | 2022-12-31 | Plyn | 6 | 287.50 | 4 | 20 |
| 9854 | 2022-12-31 | Plyn | 7 | 287.50 | 4 | 20 |
9855 rows × 6 columns
Kalkulace dostupneho vykonu¶
- vliv nahodnych odstavek
- vliv pocasi na FVE
In [7]:
df_system = apply_shutdowns(df_system)
df_system
Out[7]:
| date | type | block_no | power | priority | shutdown_prob | available_power | |
|---|---|---|---|---|---|---|---|
| 0 | 2022-01-01 | FVE | 0 | 2100.00 | 1 | 40 | 2100.00 |
| 1 | 2022-01-01 | Jadro | 0 | 716.67 | 2 | 10 | 716.67 |
| 2 | 2022-01-01 | Jadro | 1 | 716.67 | 2 | 10 | 716.67 |
| 3 | 2022-01-01 | Jadro | 2 | 716.67 | 2 | 10 | 716.67 |
| 4 | 2022-01-01 | Jadro | 3 | 716.67 | 2 | 10 | 716.67 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 9850 | 2022-12-31 | Plyn | 3 | 287.50 | 4 | 20 | 287.50 |
| 9851 | 2022-12-31 | Plyn | 4 | 287.50 | 4 | 20 | 287.50 |
| 9852 | 2022-12-31 | Plyn | 5 | 287.50 | 4 | 20 | 287.50 |
| 9853 | 2022-12-31 | Plyn | 6 | 287.50 | 4 | 20 | 287.50 |
| 9854 | 2022-12-31 | Plyn | 7 | 287.50 | 4 | 20 | 287.50 |
9855 rows × 7 columns
In [8]:
yearly_params
Out[8]:
| leden | cervenec | zdroj | |
|---|---|---|---|
| Rocni cyklus | |||
| Spotreba [GWh] | 8500 | 6500 | https://www.eru.cz/rocni-zprava-o-provozu-elek... |
| Utilizace FVE [%] | 10 | 50 | NaN |
In [9]:
fve_utilization = yearly_params.loc["Utilizace FVE [%]"]
mask = df_system["type"] == "FVE"
df_system.loc[mask, "available_power"] = adjust_fve_power(
df_system.loc[mask, "available_power"],
january_utilization=fve_utilization["leden"],
july_utilization=fve_utilization["cervenec"],
)
Spotreba¶
- pridam denni spotrebu
- vypnu nadbytecne zdroje
- spocitam dny s nedodavkou
In [10]:
demand_params_MWh = yearly_params.loc["Spotreba [GWh]"] * 1000
demand = prepare_demand(days, demand_params_MWh["leden"], demand_params_MWh["cervenec"])
df_system = df_system.merge(demand, on="date")
df_system
Out[10]:
| date | type | block_no | power | priority | shutdown_prob | available_power | demand | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2022-01-01 | FVE | 0 | 2100.00 | 1 | 40 | 210.00 | 11805.56 |
| 1 | 2022-01-01 | Jadro | 0 | 716.67 | 2 | 10 | 716.67 | 11805.56 |
| 2 | 2022-01-01 | Jadro | 1 | 716.67 | 2 | 10 | 716.67 | 11805.56 |
| 3 | 2022-01-01 | Jadro | 2 | 716.67 | 2 | 10 | 716.67 | 11805.56 |
| 4 | 2022-01-01 | Jadro | 3 | 716.67 | 2 | 10 | 716.67 | 11805.56 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 9850 | 2022-12-31 | Plyn | 3 | 287.50 | 4 | 20 | 287.50 | 11805.35 |
| 9851 | 2022-12-31 | Plyn | 4 | 287.50 | 4 | 20 | 287.50 | 11805.35 |
| 9852 | 2022-12-31 | Plyn | 5 | 287.50 | 4 | 20 | 287.50 | 11805.35 |
| 9853 | 2022-12-31 | Plyn | 6 | 287.50 | 4 | 20 | 287.50 | 11805.35 |
| 9854 | 2022-12-31 | Plyn | 7 | 287.50 | 4 | 20 | 287.50 | 11805.35 |
9855 rows × 8 columns
In [11]:
fig = plot_power(df_system, "available_power")
fig.show()
Vypnuti nadbytecnych zdroju¶
In [12]:
df_system.sort_values(by=["date", "priority", "available_power", "block_no"], inplace=True)
df_system["total_power"] = df_system.groupby("date")["available_power"].cumsum()
df_system["turn_off"] = (df_system["total_power"] - df_system["power"]) > df_system["demand"]
df_system = df_system.assign(final_power=lambda x: (~x.turn_off) * x.available_power)
df_system
Out[12]:
| date | type | block_no | power | priority | shutdown_prob | available_power | demand | total_power | turn_off | final_power | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2022-01-01 | FVE | 0 | 2100.00 | 1 | 40 | 210.00 | 11805.56 | 210.00 | False | 210.00 |
| 1 | 2022-01-01 | Jadro | 0 | 716.67 | 2 | 10 | 716.67 | 11805.56 | 926.67 | False | 716.67 |
| 2 | 2022-01-01 | Jadro | 1 | 716.67 | 2 | 10 | 716.67 | 11805.56 | 1643.33 | False | 716.67 |
| 3 | 2022-01-01 | Jadro | 2 | 716.67 | 2 | 10 | 716.67 | 11805.56 | 2360.00 | False | 716.67 |
| 4 | 2022-01-01 | Jadro | 3 | 716.67 | 2 | 10 | 716.67 | 11805.56 | 3076.67 | False | 716.67 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 9850 | 2022-12-31 | Plyn | 3 | 287.50 | 4 | 20 | 287.50 | 11805.35 | 11418.40 | False | 287.50 |
| 9851 | 2022-12-31 | Plyn | 4 | 287.50 | 4 | 20 | 287.50 | 11805.35 | 11705.90 | False | 287.50 |
| 9852 | 2022-12-31 | Plyn | 5 | 287.50 | 4 | 20 | 287.50 | 11805.35 | 11993.40 | False | 287.50 |
| 9853 | 2022-12-31 | Plyn | 6 | 287.50 | 4 | 20 | 287.50 | 11805.35 | 12280.90 | True | 0.00 |
| 9854 | 2022-12-31 | Plyn | 7 | 287.50 | 4 | 20 | 287.50 | 11805.35 | 12568.40 | True | 0.00 |
9855 rows × 11 columns
In [13]:
fig = plot_power(df_system, "final_power")
fig.show()
Nedodavka¶
In [14]:
df_missed = df_system.groupby("date")[["total_power", "demand"]].max()
df_missed = df_missed.assign(missed=lambda x: np.maximum(x.demand - x.total_power, 0))
df_missed.reset_index(inplace=True)
df_missed[df_missed["missed"] > 0]
Out[14]:
| date | total_power | demand | missed | |
|---|---|---|---|---|
| 0 | 2022-01-01 | 11510.00 | 11805.56 | 295.56 |
| 3 | 2022-01-04 | 11012.50 | 11803.70 | 791.20 |
| 9 | 2022-01-10 | 11148.36 | 11788.92 | 640.56 |
| 10 | 2022-01-11 | 10787.04 | 11785.03 | 997.99 |
| 12 | 2022-01-13 | 10802.26 | 11776.03 | 973.77 |
| ... | ... | ... | ... | ... |
| 356 | 2022-12-23 | 9733.33 | 11788.92 | 2055.59 |
| 357 | 2022-12-24 | 9512.50 | 11792.41 | 2279.91 |
| 361 | 2022-12-28 | 11429.17 | 11802.26 | 373.10 |
| 362 | 2022-12-29 | 11510.56 | 11803.70 | 293.14 |
| 363 | 2022-12-30 | 11431.08 | 11804.73 | 373.65 |
63 rows × 4 columns
In [15]:
df_missed.loc[df_missed["missed"] > 0, "missed"].agg({"sum": "sum", "count": "count"})
Out[15]:
sum 59807.45 count 63.00 Name: missed, dtype: float64
In [16]:
# ax = df_missed.plot.line(x="date", y="missed")
# ax.set_ylabel("Missing power [MW]")
fig = px.bar(df_missed, x="date", y="missed")
fig.update_layout(
title_text="Unsufficient supply", # title of plot
xaxis_title_text="Date", # xaxis label
yaxis_title_text="Missing power [MW]", # yaxis label
)
fig.show()
Utilizace zdroju¶
In [17]:
df_utilization = (
df_system.groupby("type")[["power", "available_power", "final_power"]]
.sum()
.assign(
utilization_avail=lambda x: x.available_power / x.power * 100,
utilization_final=lambda x: x.final_power / x.power * 100,
)
)
df_utilization
Out[17]:
| power | available_power | final_power | utilization_avail | utilization_final | |
|---|---|---|---|---|---|
| type | |||||
| FVE | 766500.00 | 136191.73 | 136191.73 | 17.77 | 17.77 |
| Jadro | 1569500.00 | 1419000.00 | 1419000.00 | 90.41 | 90.41 |
| Uhli | 3431000.00 | 2266183.33 | 2057816.67 | 66.05 | 59.98 |
| Plyn | 839500.00 | 672750.00 | 216200.00 | 80.14 | 25.75 |
In [18]:
fig = plot_utilization(df_utilization)
fig.show()
In [19]:
df_total_energy = df_system.groupby("type")[["final_power"]].sum()
df_total_energy["final_energy_GWh"] = df_total_energy["final_power"] * 24 / 1000
df_total_energy["mix_percent"] = df_total_energy["final_power"] / df_total_energy["final_power"].sum() * 100
df_total_energy.reset_index(inplace=True)
df_total_energy
Out[19]:
| type | final_power | final_energy_GWh | mix_percent | |
|---|---|---|---|---|
| 0 | FVE | 136191.73 | 3268.60 | 3.56 |
| 1 | Jadro | 1419000.00 | 34056.00 | 37.06 |
| 2 | Uhli | 2057816.67 | 49387.60 | 53.74 |
| 3 | Plyn | 216200.00 | 5188.80 | 5.65 |
In [20]:
fig = plot_total_energy(df_total_energy)
Monte Carlo simulace¶
In [84]:
df_results_missed, df_results_power = run_monte_carlo("./parametry.xlsx", 30)
0%| | 0/30 [00:00<?, ?it/s]100%|██████████| 30/30 [00:00<00:00, 30.39it/s]
In [85]:
fig = px.scatter(df_results_missed[df_results_missed["missed"] > 0], x="date", y="missed", color="replica")
fig.update_layout(
title_text="Energy not served", # title of plot
yaxis_title_text="Missing power [MW]", # xaxis label
xaxis_title_text="Date", # yaxis label
)
fig.show()
In [86]:
fig = px.histogram(
df_results_missed[df_results_missed["missed"] > 0].groupby("replica")["missed"].agg(["sum"]), x="sum", nbins=10
)
fig.update_layout(
title_text="Energy not served", xaxis_title_text="Missing power [MW]", bargap=0.1 # title of plot # xaxis label
)
In [87]:
fig = px.histogram(
df_results_missed[df_results_missed["missed"] > 0].groupby("replica")["missed"].agg(["count"]), x="count", nbins=10
)
fig.update_layout(
title_text="Days with missing power", # title of plot
xaxis_title_text="Number of days", # xaxis label
bargap=0.1,
)
In [88]:
fig = px.bar(
df_results_power[["type", "final_energy_GWh"]]
.groupby("type")
.agg(["mean", "std"])
.droplevel(level=0, axis=1)
.reset_index(),
x="type",
y="mean",
error_y="std",
color="type",
)
fig.update_layout(
title_text="Energy mix",
yaxis_title_text="Total energy delivered [GWh]",
xaxis_title_text="Source type",
showlegend=False,
)
fig.show()